﻿using Eps.Ai.Common;
using Sylan.Common.Util;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InfonavaEye.common
{
    public class AutoShotHelper
    {

        private static AutoShotHelper instance = null;

       static Dictionary<string, string> hexStrDict = new Dictionary<string, string>();
        static bool autoShotOpen = false;
        public static AutoShotHelper Instance
        {
            get
            {
                if (instance is null){
                    instance = new AutoShotHelper();
                    iniCommand();
                }
                return instance;
            }
        }
        private static void iniCommand() {
            hexStrDict.Add("7", "A510000762EF");
            hexStrDict.Add("8", "A510000822EB");
            hexStrDict.Add("9", "A5100009E32B");
            hexStrDict.Add("10", "A510000AA32A");
            hexStrDict.Add("11", "A510000B62EA");
            hexStrDict.Add("12", "A510000C2328");
            hexStrDict.Add("13", "A510000DE2E8");
            hexStrDict.Add("14", "A510000EA2E9");
            hexStrDict.Add("15", "A510000F6329");
            hexStrDict.Add("16", "A510001022E1");
            hexStrDict.Add("17", "A5100011E321");
            hexStrDict.Add("18", "A5100012A320");
            hexStrDict.Add("19", "A510001362E0");

            hexStrDict.Add("20", "A51000142322");
            hexStrDict.Add("21", "A5100015E2E2");
            hexStrDict.Add("22", "A5100016A2E3");
            hexStrDict.Add("23", "A51000176323");
            hexStrDict.Add("24", "A51000182327");
            hexStrDict.Add("25", "A5100019E2E7");
            hexStrDict.Add("26", "A510001AA2E6");
            hexStrDict.Add("27", "A510001B6326");
            hexStrDict.Add("28", "A510001C22E4");
            hexStrDict.Add("29", "A510001DE324");

            hexStrDict.Add("30", "A510001EA325");
            hexStrDict.Add("31", "A510001F62E5");
            hexStrDict.Add("32", "A510002022F5");
            hexStrDict.Add("33", "A5100021E335");
            hexStrDict.Add("34", "A5100022A334");
            hexStrDict.Add("35", "A510002362F4");
            hexStrDict.Add("36", "A51000242336");
            hexStrDict.Add("37", "A5100025E2F6");
            hexStrDict.Add("38", "A5100026A2F7");
            hexStrDict.Add("39", "A51000276337");

            hexStrDict.Add("40", "A51000282333");
            hexStrDict.Add("41", "A5100029E2F3");
            hexStrDict.Add("42", "A510002AA2F2");
            hexStrDict.Add("43", "A510002B6332");
            hexStrDict.Add("44", "A510002C22F0");
            hexStrDict.Add("45", "A510002DE330");
        }

        public AutoShotHelper() {
            if (autoShotSerialPort == null)
            {
                autoShotSerialPort = new SerialPort();
                this.OpenSerialPort(Config.AUTOSHOT_COM,115200,0,8,1);
            }
        }


        /// <summary>
        /// 初始化 串行端口资源
        /// </summary>
        private SerialPort autoShotSerialPort = null;

        public bool sendMsg(string data) {
            if (!autoShotOpen) {
                Console.WriteLine("电动镜头串口通信未打开");
                return false; 
            }
            string hexStr = hexStrDict[data];
             byte[] content = this.strToToHexByte(hexStr);
            Console.WriteLine("向电动镜头发送的指令：     " + hexStr);

            /*  byte[] crc16cBy = CRC16_C(Encoding.UTF8.GetBytes(data));
               StringBuilder  commondStr=new StringBuilder();
               commondStr.Append("A5");
               commondStr.Append("10");           
               double bl = double.Parse(data) * 10;
               int blInt=(int)bl;
               commondStr.Append(this.StrToHex(blInt.ToString()));
              //commondStr.Append(this.StrToHex(data));
             string crc16Hex= this.byteToHex(crc16cBy);
               Console.WriteLine("this.byteToHex(crc16cBy)==="+ crc16Hex);
               commondStr.Append(crc16Hex);
               Console.WriteLine("向电动镜头发送的指令：     "+commondStr.ToString());
               byte[] content = this.strToToHexByte(commondStr.ToString());*/
            try
            {
                autoShotSerialPort.Write(content, 0, content.Length);
                return true;
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e);
            }
            return false;
        }

        /// <summary>
        /// 设置 串口配置
        /// </summary>
        /// <param name="portName">串口号</param>
        /// <param name="baudRate">波特率</param>
        /// <param name="parity">校验位</param>
        /// <param name="dataBits">数据位</param>
        /// <param name="stopBits">停止位</param>
        private void SetSerialPortConfig(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            // 串口 参数设置
            autoShotSerialPort.PortName = portName;
            autoShotSerialPort.BaudRate = baudRate;
            switch (parity)
            {
                case 0:
                default:
                    autoShotSerialPort.Parity = Parity.None;
                    break;

                case 1:
                    autoShotSerialPort.Parity = Parity.Odd;
                    break;

                case 2:
                    autoShotSerialPort.Parity = Parity.Even;
                    break;

                case 3:
                    autoShotSerialPort.Parity = Parity.Mark;
                    break;

                case 4:
                    autoShotSerialPort.Parity = Parity.Space;
                    break;
            }
            autoShotSerialPort.DataBits = ((4 < dataBits) && (dataBits < 9)) ? dataBits : 8;
            switch (stopBits)
            {
                case 0:
                    autoShotSerialPort.StopBits = StopBits.None;
                    break;

                case 1:
                default:
                    autoShotSerialPort.StopBits = StopBits.One;
                    break;

                case 2:
                    autoShotSerialPort.StopBits = StopBits.OnePointFive;
                    break;

                case 3:
                    autoShotSerialPort.StopBits = StopBits.Two;
                    break;
            }
            autoShotSerialPort.ReadTimeout = -1;
            autoShotSerialPort.RtsEnable = true;
           autoShotSerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceiverd);
        }

        private void DataReceiverd(object sender, SerialDataReceivedEventArgs e)
        {
            if (e.EventType == System.IO.Ports.SerialData.Eof) return;
            try
            {
                Logger.Write(Level.INFO, "=======================================================电动镜头串口上报数据=======================");
                byte[] ReadBuf = new byte[autoShotSerialPort.BytesToRead];
                autoShotSerialPort.Read(ReadBuf, 0, ReadBuf.Length);
                autoShotSerialPort.DiscardInBuffer();
                string serialDataStr = System.Text.Encoding.UTF8.GetString(ReadBuf);
                Logger.Write(Level.INFO, "电动镜头串口最开始读取到的数据==" + serialDataStr);
            }
            catch (System.Exception ex)
            {
                throw ex;
            }

        } 

            /// <summary>
            /// 打开串口
            /// </summary>
            /// <param name="portName">串口号</param>
            /// <param name="baudRate">波特率</param>
            /// <param name="parity">校验位</param>
            /// <param name="dataBits">数据位</param>
            /// <param name="stopBits">停止位</param>
       public void OpenSerialPort(string portName, int baudRate, int parity, int dataBits, int stopBits)
       {
            try
            {
                SetSerialPortConfig(portName, baudRate, parity, dataBits, stopBits);
                autoShotSerialPort.Open();
                autoShotOpen=true;
            }
            catch (System.Exception ex)
            {
                autoShotOpen = false;
                Console.WriteLine(ex.ToString());
            }
       }

        /// <summary>
        /// 关闭串口
        /// </summary>
        public void CloseSerialPort()
        {
            try
            {
                autoShotSerialPort.Close();
                autoShotOpen = false;
            }
            catch (System.Exception ex)
            {
            }
        }


        /// <summary>
        /// 计算CRC16
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private byte[] CRC16_C(byte[] data)
        {
            byte CRC16Lo;
            byte CRC16Hi;           //CRC寄存器 
            byte CL; byte CH;       //多项式码 ccitt的多项式是x16+x12+x5+1,多项式码是0x1021,但由于ccitt是默认先传LSB而不是MSB，故这里应该将多项式码按bit反转得到0x8408
            byte SaveHi; byte SaveLo;
            byte[] tmpData;
            int Flag;
            CRC16Lo = 0xFF;
            CRC16Hi = 0xFF;
            CL = 0x08;
            CH = 0x84;
            tmpData = data;
            for (int i = 0; i < tmpData.Length; i++)
            {
                CRC16Lo = (byte)(CRC16Lo ^ tmpData[i]); //每一个数据与CRC寄存器进行异或 
                for (Flag = 0; Flag <= 7; Flag++)
                {
                    SaveHi = CRC16Hi;
                    SaveLo = CRC16Lo;
                    CRC16Hi = (byte)(CRC16Hi >> 1);      //高位右移一位 
                    CRC16Lo = (byte)(CRC16Lo >> 1);      //低位右移一位 
                    if ((SaveHi & 0x01) == 0x01) //如果高位字节最后一位为1 
                    {
                        CRC16Lo = (byte)(CRC16Lo | 0x80);   //则低位字节右移后前面补1 
                    }             //否则自动补0 
                    if ((SaveLo & 0x01) == 0x01) //如果LSB为1，则与多项式码进行异或 
                    {
                        CRC16Hi = (byte)(CRC16Hi ^ CH);
                        CRC16Lo = (byte)(CRC16Lo ^ CL);
                    }
                }
            }
            byte[] ReturnData = new byte[2];
            ReturnData[0] = CRC16Hi;       //CRC高位 
            ReturnData[1] = CRC16Lo;       //CRC低位 
            return ReturnData;
        }


        /// <summary>
        /// 16进制转字节
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private byte[] strToToHexByte(string hexString)
        {
            hexString = hexString.Replace(" ", "");
            if ((hexString.Length % 2) != 0)
                hexString += " ";
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
            return returnBytes;
        }
        /// <summary>
        /// 字符串转16进制
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public  string StrToHex(string s)
        {
            StringBuilder sb = new StringBuilder();

            byte[] arrByte = System.Text.Encoding.UTF8.GetBytes(s);
            for (int i = 0; i < arrByte.Length; i++)
            {
                sb.Append(System.Convert.ToString(arrByte[i], 16));
            }
            //Logger.Write(Level.INFO, "字符串转16进制 " + sb.ToString().Trim());
            return sb.ToString().Trim();
        }

        /// <summary>
        /// 字符串字节转16进制
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public string byteToHex(byte[] arrByte)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < arrByte.Length; i++)
            {
                sb.Append(System.Convert.ToString(arrByte[i], 16));
            }
            return sb.ToString().Trim();
        }
    }
}
